package server;

import interfaces.DataRepository;
import interfaces.SearchDataBase;
import interfaces.UserRepository;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.ServerSocket;
import java.text.SimpleDateFormat;
import java.util.Date;
import logger.ForumLogger;
import persistence.jdbc.JDBCDataRepository;
import persistence.jdbc.JDBCUserRepository;
import search.CompassSearchEngine;
import search.SearchDBManager;
import domain.items.MetaData;

/**
 * this is the controller of the server application
 *
 * @author awarmanX
 *
 */
public class ForumServer {

	/**
	 * singleton instance of the server
	 */
	private static ForumServer _INSTANCE = null;

	/**
	 * the accepting socket
	 */
	private ServerSocket _serverSocket;

	/**
	 * currently a random port is picked each time (for debugging) to be
	 * replaced by a PERMANENT port
	 */
	private int _port;

	/**
	 * access to the user repository
	 */
	private UserRepository _userRepository;

	/**
	 * access to the data repository
	 */
	private DataRepository _dataRepository;

	/**
	 * access to the Search Engine data repository
	 */
	private SearchDBManager _searchDataRepository = new SearchDBManager();

	/**
	 * metaData of the forum
	 */
	public static MetaData _metaData;

	/**
	 * number of users currently connected
	 */
	private int numOfCurrUsers;

	private SimpleDateFormat _javaDateFormat;

	/**
	 * constructor
	 */
	private ForumServer() {
		try {
			this._serverSocket = new ServerSocket(0);
			this._port = this._serverSocket.getLocalPort();
			putPort();

			//_metaData = (MetaData) XMLUtils.loadDB(MetaData.FILE_NAME);
			_metaData = new MetaData();
			CompassSearchEngine.getInstance(); //create the single instance of the Compass
						
			/* using SQL server */
			this._userRepository = new JDBCUserRepository();
			this._dataRepository = new JDBCDataRepository();

			/* using XML files */
			// this._userRepository = new XMLUserRepository("users.xml");
			// this._dataRepository = new XMLDataRepository("forum.xml");

			// for fast performance, disable this line
			// this._searchDataRepository =
			// (SearchDBManager)XMLUtils.loadDB(SearchDBManager.FILE_NAME);

			numOfCurrUsers = 0;

			this._javaDateFormat = new SimpleDateFormat("dd/MM/yy HH:mm");

		} catch (IOException e) {
			ForumLogger.logIOException();
		}
	}


	public static ForumServer getInstance(){
		if(_INSTANCE == null){
			_INSTANCE = new ForumServer();
		}
		return _INSTANCE;
	}


	/**
	 * let the client know of the chosen port
	 */
	private void putPort() {
		Writer output = null;
		try {
			String text = "" + _port;
			File file = new File("port.txt");
			output = new BufferedWriter(new FileWriter(file));
			output.write(text);
			output.close();
		} catch (Exception e) {
		}
	}

	/**
	 * @return the _serverSocket
	 */
	public ServerSocket get_serverSocket() {
		return _serverSocket;
	}

	/**
	 * @return the _port
	 */
	public int get_port() {
		return _port;
	}

	/**
	 * @return the _userRepository
	 */
	public UserRepository getUserRepository() {
		return _userRepository;
	}

	/**
	 * @return the _dataRepository
	 */
	public DataRepository getDataRepository() {
		return _dataRepository;
	}

	/**
	 * @return the _searchDataRepository
	 */
	public SearchDataBase getSearchDB() {
		return this._searchDataRepository;
	}

	/**
	 * @return number of users and current time
	 */
	public synchronized String getCurrUsersStatus() {
		String ans;
		int numOfUsers = this.getNumOfCurrUsers();
		if (numOfUsers == 1){
			  ans = "You're the only ranger here!   "
			+ this._javaDateFormat.format(new Date());
		}
		else {
			ans =
				numOfUsers + " rangers currently connected   "
				+ this._javaDateFormat.format(new Date());
		}
		return ans;
	}

	/**
	 * @return the numOfCurrUsers
	 */
	public int getNumOfCurrUsers() {
		return numOfCurrUsers;
	}

	/**
	 * @param numOfCurrUsers
	 *            the numOfCurrUsers to set
	 */
	public void setNumOfCurrUsers(int upOrDown) {
		this.numOfCurrUsers = this.numOfCurrUsers + upOrDown;
	}

}
